/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package core;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;

import org.omg.DynamicAny.DynAnyPackage.TypeMismatch;
/**
 *
 * @author Sakis Vtdk
 */
public class Change implements Cloneable
{
	public Change()
	{
		//when creating the Change object the targetVersion is set to the current
		//version of the database
		this._targetVersion = Database.getDatabase().getCurrentVersion();
		this._isReverse = false;

		log.debug("New Change object has been created");
	}

	@Override
	public Change clone() throws CloneNotSupportedException
	{
		Change cloneChange = (Change) super.clone();
		cloneChange.setTargetVersion(this._targetVersion);

		return cloneChange;
	}

	//TODO: Create generate summary method

	// <editor-fold desc="Getters">

	/**
	 * Returns the summary of this change
	 * 
	 * @return The summary of the change
	 */
	public String getChangeSummary()
	{
		return this._changeSummary;
	}

	/**
	 * Returns the type of change. Can be CREATE | UPDATE | DELETE
	 * 
	 * @return The type of the change
	 */
	public String getType()
	{
		return this._type.name();
	}

	/**
	 * Returns what object has changed. Can be TABLE | COLUMN
	 * 
	 * @return The object that has changed
	 */
	public String getObjectChanged()
	{
		return this._objectChanged.name();
	}

	public int getId()
	{
		return _id;
	}

	public String getNewValue()
	{
		return _newValue;
	}

	public String getOldValue()
	{
		return _oldValue;
	}

	public String getWhatChanged()
	{
		return _whatChanged.toString();
	}

	public int getParentId()
	{
		return _parentId;
	}

	public BigDecimal getTargetVersion()
	{
		return this._targetVersion;
	}
	
	public String getName()
	{
		return _name;
	}

	public String getParentName()
	{
		return _parentName;
	}

	public boolean isReverse()
	{
		return _isReverse;
	}

	//</editor-fold>

	//<editor-fold desc="Setters">

	/**
	 * Sets the summary for this change
	 * 
	 * @param summary The summary for this change
	 */
	public void setChangeSummary(String summary)
	{
		this._changeSummary = addDateTimeSummary(summary);
	}

	/**
	 * Adds date and time to the summary string if it isn't already there
	 * 
	 * @param summary The summary string
	 * @return The summary after the edit 
	 */
	private String addDateTimeSummary(String summary)
	{
		if(!summaryHasDateTime(summary))
		{
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			Date date = new Date();

			summary = dateFormat.format(date) +" : "+ summary;
		}

		return summary;
	}

	/**
	 * Checks if the summary already has date and time
	 * 
	 * @param summary The string to be checked 
	 * @return True if summary has date and time, false otherwise
	 */
	private boolean summaryHasDateTime(String summary)
	{
		//The pattern is of the form: 
		//  YYYY/MM/DD HH:MM:SS
		Pattern DateTimePattern = Pattern.compile("[0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}");
		Matcher matcher = DateTimePattern.matcher(summary);

		return matcher.find();
	}

	/**
	 * Set what has changed i.e. table, column etc.
	 * The object must be the one on which the action has happened.
	 * 
	 * E.g.: If a column is created within a table, the objectChanged must be
	 * column, NOT table.
	 * 
	 * @param _objectChanged 
	 */
	public void setObjectChanged(ObjectChanged _objectChanged)
	{
		this._objectChanged = _objectChanged;
	}

	public void setObjectChanged(String objectChanged) throws TypeMismatch
	{
		if(objectChanged.equalsIgnoreCase("COLUMN"))
		{
			this._objectChanged = ObjectChanged.COLUMN;
		}
		else if(objectChanged.equalsIgnoreCase("TABLE"))
		{
			this._objectChanged = ObjectChanged.TABLE;
		}
		else
		{
			throw new TypeMismatch("TypeMismatch Excpetion: Unknown object changed!");
		}
	}

	/**
	 * Set what type of change was made, i.e. Create, update, delete
	 * 
	 * @param _type 
	 */
	public void setType(Type _type)
	{
		this._type = _type;
	}
	
	public void setType(String type) throws TypeMismatch
	{
		if(type.equalsIgnoreCase("CREATE"))
		{
			this._type = Type.CREATE;
		}
		else if(type.equalsIgnoreCase("UPDATE"))
		{
			this._type = Type.UPDATE;
		}
		else if(type.equalsIgnoreCase("DELETE"))
		{
			this._type = Type.DELETE;
		}
		else
		{
			throw new TypeMismatch("TypeMismatch Exception: Unknown type of change!");
		}
	}

	public void setNewValue(String _newValue)
	{
		this._newValue = _newValue;
	}

	public void setOldValue(String _oldValue)
	{
		this._oldValue = _oldValue;
	}

	public void setParentId(int _parentId)
	{
		this._parentId = _parentId;
	}

	/**
	 * Set the thing the changed i.e. the name, the collation, data type, etc
	 * 
	 * @param _whatChanged 
	 */
	public void setWhatChanged(WhatChanged _whatChanged)
	{
		this._whatChanged = _whatChanged;
	}

	public void setWhatChanged(String whatChanged)
	{
		this._whatChanged = WhatChanged.valueOf(whatChanged.toUpperCase(Locale.ENGLISH));
	}

	public void setId(int _id)
	{
		this._id = _id;
	}

	public void setTargetVersion(BigDecimal version)
	{
		this._targetVersion = version;
	}

	public void setName(String name)
	{
		this._name = name;
	}

	public void setParentName(String parentName)
	{
		this._parentName = parentName;
	}

	public void setIsReverse(boolean isReverse)
	{
		this._isReverse = isReverse;
	}
		
	//</editor-fold>
	
	//<editor-fold desc="Private variables">

	public enum Type {CREATE, UPDATE, DELETE};
	public enum ObjectChanged {COLUMN, TABLE};
	public enum WhatChanged {NAME, DATA_TYPE, DATA_SIZE, DEFAULT_VALUE, AUTO_INCREMENT, PRIMARY_KEY};

	/**
	 * The type of the change; CREATE || UPDATE || DELETE
	 */
	private Type _type;

	/**
	 * The object that was changed; COLUMN || TABLE.
	 * NOTE: If a column is created within a table, the objectChanged is COLUMN
	 */
	private ObjectChanged _objectChanged;

	/**
	 * In case of UPDATE, what was the thing that was updated. e.g. Name, DataType, etc
	 */
	private WhatChanged _whatChanged;	

	/**
	 * The name of the table this column belongs to. (ONLY for COLUMN)
	 */
	private String _parentName;

	/**
	 * The name of the object that was changed
	 */
	private String _name;

	/**
	 * The old value of the thing that was updated
	 */
	private String _oldValue;

	/**
	 * The new value of the thing that was updated
	 */
	private String _newValue;

	/**
	 * The id of the parent. If the change is for a table, this id is set to -1
	 */
	private int _parentId;

	/**
	 * The id of the object that was changed
	 */
	private int _id;

	/**
	 * The version that this change will bring the database
	 */
	private BigDecimal _targetVersion;

	/**
	 * The summary of this change. Only informational
	 */
	private String _changeSummary;

	/**
	 * True if the change is for a previous version
	 */
	private boolean _isReverse;
	
	/**
	 * Logger instance
	 */
	private static Logger log = Logger.getLogger(Change.class);

	//</editor-fold>
}
